<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ja" lang="ja">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<link href="../css/main.css" media="all" rel="stylesheet" type="text/css" />
<link href="../css/highlight.css" media="all" rel="stylesheet" type="text/css" />
<link href="../css/print.css" media="print" rel="stylesheet" type="text/css" />
<title>第9章 - リンクとルーティングシステム</title>
</head>

<body>
<div class="navigation">

<table width="100%">
<tr>
<td width="40%" align="left"><a href="08-Inside-the-Model-Layer.html">前の章</a></td>
<td width="20%" align="center"><a href="index.html">ホーム</a></td>
<td width="40%" align="right"><a href="10-Forms.html">次の章</a></td>
</tr>
</table>
<hr/>
</div>

<div>
<a name="chapter.9.links.and.the.routing.system" id="chapter.9.links.and.the.routing.system"></a><h1>第9章 - リンクとルーティングシステム</h1>

<p>リンクとURLはWebアプリケーションのフレームワークにおいて特別な扱いをする価値があります。アプリケーション唯一のエントリーポイント(フロントコントローラー)とヘルパーを利用することでURLの動作方法とそれらの表現方法を完全に分離できるようになります。この機能はルーティング(routing)と呼ばれます。ルーティングはアプリケーションをガジェットよりもユーザーフレンドリでセキュアにするための便利なツールです。この章ではsymfonyのアプリケーションでURLを扱うために知る必要があることをすべてお伝えします。</p>

<ul>
<li>ルーティングシステムとは何か、またそれがどのように動作するのか</li>
<li>対外的なURLのルーティングを有効にするためにテンプレート内でリンクヘルパーを使う方法</li>
<li>URLの表示方法を変更するためにルーティングルールを変更する方法</li>
</ul>

<p>ルーティングのパフォーマンスと最後の仕上げを習得するためにいくつかのトリックを見ることにもなります。</p>

<div class="toc">
<dl>
<dt><a href="#what.is.routing">9.1. ルーティングとは何か？</a></dt>
<dd><dl>
<dt><a href="#urls.as.server.instructions">9.1.1. サーバーに対する命令としてのURL</a></dt>
<dt><a href="#urls.as.part.of.the.interface">9.1.2. インターフェイスの一部としてのURL</a></dt>
<dt><a href="#how.it.works">9.1.3. どのように動作するのか</a></dt>
</dl></dd>
<dt><a href="#url.rewriting">9.2. URLを書き換える</a></dt>
<dt><a href="#link.helpers">9.3. リンクヘルパー</a></dt>
<dd><dl>
<dt><a href="#hyperlinks.buttons.and.forms">9.3.1. ハイパーリンク、ボタン、とフォーム</a></dt>
<dt><a href="#link.helper.options">9.3.2. リンクヘルパーのオプション</a></dt>
<dt><a href="#fake.get.and.post.options">9.3.3. フェイクのGETとPOSTオプション</a></dt>
<dt><a href="#forcing.request.parameters.as.get.variables">9.3.4. リクエストパラメーターをGET変数として強制する</a></dt>
<dt><a href="#using.absolute.paths">9.3.5. 絶対パスを使う</a></dt>
</dl></dd>
<dt><a href="#routing.configuration">9.4. ルーティングの設定</a></dt>
<dd><dl>
<dt><a href="#rules.and.patterns">9.4.1. ルールとパターン</a></dt>
<dt><a href="#pattern.constraints">9.4.2. パターンの制約</a></dt>
<dt><a href="#setting.default.values">9.4.3. デフォルト値を設定する</a></dt>
<dt><a href="#speeding.up.routing.by.using.the.rule.name">9.4.4. ルールの名前を利用してルーティングを加速する</a></dt>
<dt><a href="#adding.an.html.extension">9.4.5. .html拡張子を追加する</a></dt>
<dt><a href="#creating.rules.without.routing.yml">9.4.6. routing.ymlなしでルールを作成する</a></dt>
</dl></dd>
<dt><a href="#dealing.with.routes.in.actions">9.5. アクションのなかでrouteを処理する</a></dt>
<dt><a href="#summary">9.6. まとめ</a></dt>
</dl>
</div>
<a name="what.is.routing" id="what.is.routing"></a><h2>ルーティングとは何か？</h2>

<p>ルーティング(routing)とはURLをよりユーザーフレンドリに書き換えるメカニズムです。しかし、なぜこれが重要なのかを理解するには、URLについて数分考えなければなりません。</p>

<a name="urls.as.server.instructions" id="urls.as.server.instructions"></a><h3>サーバーに対する命令としてのURL</h3>

<p>URLはユーザーが望むアクションを成立させるためにブラウザーからの情報をサーバーに運びます。たとえば、つぎの例のように、伝統的なURLはリクエストを完了させるために必要なスクリプトへのファイルパスとパラメーターを含みます:</p>

<pre><code>http://www.example.com/web/controller/article.php?id=123456&amp;format_code=6532
</code></pre>

<p>このURLはアプリケーションのアーキテクチャとデータベースに関する情報を運びます。通常、開発者はインターフェイス内のアプリケーションのインフラを隠します(たとえば、開発者は"QZ7.65"よりも"個人のプロファイルページ"のようなページタイトルを選びます)。アプリケーション内部への重要な手がかりをURLに露出することはこの努力に相反することで重大な欠陥を晒すことになります。</p>

<ul>
<li>URLに表示される技術上のデータは潜在的なセキュリティの欠点を作ります。前の例において、悪意のあるユーザーが<code>id</code>パラメーターの値を変更したら何が起こるでしょうか？アプリケーションがデータベースへの直接のインターフェイスを提供することは何を意味するのでしょうか？もしくはユーザーが面白半分にほかのスクリプト名、たとえば<code>admin.php</code>を試したらどうなるでしょうか？一般的に、生のURLを使うとアプリケーションを簡単に不正利用するための方法を提供することになるので、これらの方法によってセキュリティの管理がほとんど不可能になります。</li>
<li>不明瞭なURLを使うと、どこに表示されようとも鬱陶しく、周囲の内容の印象が希薄になります。そして今日において、URLはアドレバーだけに表示されません。検索結果と同様に、これらはユーザーがリンクの上にマウスをホーバーしたときにも表示されます。ユーザーが情報を探すとき、図9-1のようなややこしいURLよりも、ユーザーのために探しものに関して簡単に理解できる手がかりを与えたいと開発者は願うことでしょう。</li>
</ul>

<p>図9-1 - URLは検索結果などの多くの場所で表示される</p>

<p><img src="images/F0901.png" alt="URLは検索結果などの多くの場所で表示される" title="URLは検索結果などの多くの場所で表示される" /></p>

<ul>
<li>URLの1つを変更しなければならない場合(たとえば、スクリプト名もしくはパラメーターの1つが修正される場合)、このURLへのすべてのリンクも同様に変更しなければなりません。コントローラー構造の修正作業は重量級で高くつくので、アジャイル開発において理想的ではありません。</li>
</ul>

<p>symfonyがフロントコントローラーのパラダイムを利用しない場合、事態はもっと悪化する可能性があります; すなわち、つぎのように、アプリケーションが、多くのディレクトリのなかで、インターネットからアクセスできるスクリプトが多く含まれている場合です:</p>

<pre><code>http://www.example.com/web/gallery/album.php?name=my%20holidays
http://www.example.com/web/weblog/public/post/list.php
http://www.example.com/web/general/content/page.php?name=about%20us
</code></pre>

<p>この場合、開発者はURLの構造をファイル構造とマッチさせる必要があり、どちらかの構造を変更したときに、結果は悪夢のようなメンテナンス作業になります。</p>

<a name="urls.as.part.of.the.interface" id="urls.as.part.of.the.interface"></a><h3>インターフェイスの一部としてのURL</h3>

<p>ルーティングの背後にあるアイディアはURLをインターフェイスの一部としてみなすことです。アプリケーションは情報をユーザーにもたらすためにURLを整形し、ユーザーはアプリケーションのリソースにアクセスするためにURLを利用します。</p>

<p>これはsymfonyのアプリケーションで実現可能です。エンドユーザーに表示されるURLはリクエストを実行するために必要なサーバーへの命令とは無関係だからです。代わりに、URLをリクエストされるリソースに関連づけして、自由に形式を整えることができます。たとえば、symfonyはつぎのURLを理解し、この章の最初のURLのように同じページを表示できます:</p>

<pre><code>http://www.example.com/articles/finance/2006/activity-breakdown.html 
</code></pre>

<p>恩恵は計り知れません:</p>

<ul>
<li>URLは実際に何かを意味するので、これはユーザーがリンクの背後にあるページのなかに望むものが含まれるかどうかを判断するための助けになります。リンクは返すリソースに関して追加の詳細内容を含めることができます。これはとりわけ検索エンジンの結果に対して役立ちます。加えて、URLは時にページタイトルの参照なしに表示されるので(URLをEメールのメッセージにコピーするときを考えてください)、この場合、そのURLはそれ自身が何らかの意味を持たなければなりません。ユーザーフレンドリなURLの例に関しては図9-2をご覧ください。</li>
</ul>

<p>図9-2 - 刊行日のように、URLはページに関する追加情報を運ぶ</p>

<p><img src="images/F0902.png" alt="刊行日のように、URLはページに関する追加情報を運ぶ" title="刊行日のように、URLはページに関する追加情報を運ぶ" /></p>

<ul>
<li>紙のドキュメントに書かれているURLは入力しやすく覚えやすいものにすべきです。あなたの名刺に会社のWebサイトが<code>http://www.example.com/controller/web/index.jsp?id=ERD4</code>と記載されていたら、多くの訪問者を得ることはないでしょう。</li>
<li><p>URLは、 直感的な方法でアクションを実行するもしくは情報を読みとるために、独自のコマンドラインになることができます。このような機能を提供するアプリケーションによってパワーユーザーは速く作業を行うことができるようになります。</p>

<pre><code>// 結果のリスト: 結果のリストを絞るために新しいタグを追加する
http://del.icio.us/tag/symfony+ajax
// ユーザーのプロファイルページ: 別のユーザープロファイルを取得するために名前を変更する
http://www.askeet.com/user/francois
</code></pre></li>
<li><p>URLの整形方法とアクションの名前/パラメーターを、それぞれ個別に修正することで、変更できます。全体的に、アプリケーションをゴチャゴチャにすることなく、最初に開発をしてあとでURLの形式を整えることができます。</p></li>
<li>アプリケーションの内部を再編成するときでも、URLは外部の世界に対して同じ状態を保つことができます。動的なページをブックマークできるようになるので、URLの永続性は必須です。</li>
<li>検索エンジンはWebサイトをインデックスに登録するとき、(<code>.php</code>、<code>.asp</code>などで終わる)動的なページを無視しがちです。検索エンジンが動的なページに遭遇したときでも、静的な内容をブラウジングしていると考えさせるためにURLの形式を整えることができます。結果としてインデックスに登録されるアプリケーションのページの内容がよくなります。</li>
<li>より安全です。承認されていないURLを閲覧しようとすると開発者が指定したページにリダイレクトされるので、ユーザーが試しにURLを入力してもWebのrootのファイル構造を閲覧することはできません。リクエストによって呼び出された実際のスクリプト名は、そのパラメーターと同様に、隠匿されています。</li>
</ul>

<p>ユーザーと実際のスクリプト名とリクエストパラメーターに表示されるURL間の対応は設定を通して修正できるパターンに基づいた、ルーティングシステムによって実現されます。</p>

<blockquote class="note"><p>
  アセット(asset)はどうでしょうか？幸運にも、URLのアセット(画像、スタイルシート、とJavaScript)はブラウジングの間は大量に表示されないので、これらに対してルーティングを実際に設定する必要はありません。symfonyにおいて、すべてのアセットは<code>web/</code>ディレクトリに設置され、URLはファイルシステムの設置場所に一致します。しかしながら、アセットヘルパー内部で生成されたURLを利用することで(アクションによって処理された)動的なアセットを管理できます。たとえば、動的に生成された画像を表示するには、<code>image_tag('captcha/image?key='.$key)</code>ヘルパーを使います。</p>
</blockquote>

<a name="how.it.works" id="how.it.works"></a><h3>どのように動作するのか</h3>

<p>symfonyは外部のURLと内部のURIを切り離します。これら2つを対応させる作業はルーティングシステムによって行われます。わかりやすくするために、symfonyは通常のURLの構文とよく似た内部URIのための構文を使います。リスト9-1は例を示しています。</p>

<p>リスト9-1 - 外部URLと内部URI</p>

<pre><code>// 内部のURI構文
&lt;module&gt;/&lt;action&gt;[?param1=value1][&amp;param2=value2][&amp;param3=value3]...

// 内部URIの例で、エンドユーザーに決して表示されない
article/permalink?year=2006&amp;subject=finance&amp;title=activity-breakdown

// 外部URLの例で、エンドユーザーに表示される
http://www.example.com/articles/finance/2006/activity-breakdown.html
</code></pre>

<p>ルーティングシステムを定義するには<code>routing.yml</code>という名前の特別な設定ファイルを使います。リスト9-2で示されているルールを考えます。このルールは<code>articles/*/*/*</code>のようなパターンを定義し、ワイルドカードとマッチする内容の一部を命名します(訳注：既存のルーティングファイルで試す場合、default:よりも上側にしないと機能しません。また<code>php symfony cache:clear</code>でキャッシュをクリアする必要があります)。</p>

<p>リスト9-2 - ルーティングルールのサンプル</p>

<pre><code>article_by_title:
  url:    articles/:subject/:year/:title.html
  param:  { module: article, action: permalink }
</code></pre>

<p>symfonyのアプリケーションに送信されるすべてのリクエストは最初ルーティングシステムによって分析されます(単独のフロントコントローラーによって処理されるのでシンプルです)。ルーティングシステムはリクエストされたURLとマッチするルーティングルールで定義されたパターンを探します。マッチするパターンが見つかった場合、名前つきのワイルドカードはリクエストパラメーターになり<code>param:</code>キーで定義されたものと統合されます。どのように動くのかはリスト9-3をご覧ください。</p>

<p>リスト9-3 - ルーティングシステムは入ってくるリクエストURLを解釈する</p>

<pre><code>// ユーザーがつぎの外部URLを入力する(クリックする)
http://www.example.com/articles/finance/2006/activity-breakdown.html

// フロントコントローラーはリクエストURLがarticle_by_titleルールにマッチするか見る
// ルーティングシステムはつぎのリクエストパラメーターを作成する
  'module'  =&gt; 'article'
  'action'  =&gt; 'permalink'
  'subject' =&gt; 'finance'
  'year'    =&gt; '2006'
  'title'   =&gt; 'activity-breakdown'
</code></pre>

<blockquote class="tip"><p>
  外部URLの<code>.html</code>拡張子はシンプルな飾り付けでルーティングシステムは無視します。その唯一の利点は動的なページを静的なページに見えるようにすることです。この章の後のほうにある"ルーティングの設定"でこの拡張子を有効にする方法を見ることになります。</p>
</blockquote>

<p>リクエストは<code>article</code>モジュールの<code>permalink</code>アクションに渡されます。アクションは表示する記事を決定するためにリクエストパラメーターで求められたすべての情報を持ちます。</p>

<p>しかしながらメカニズムはまったく逆のことも行わなければなりません。リンクに外部URLを表示するアプリケーションに対して、どのルールを適用するのか決定するために十分なデータを持つルーティングルールを提供しなければなりません。ルーティングを完全に無視する<code>&lt;a&gt;</code>タグで直接ハイパーリンクを書いてはなりません。代わりに、リスト9-4で示されるように特別なヘルパーを使います。</p>

<p>リスト9-4 - ルーティングシステムはテンプレート内部のURLの出力形式を整える</p>

<pre class="php">// url_for()ヘルパーは内部URIを外部URLに変換する
&lt;a href=&quot;<span class="kw2">&lt;?php</span> <span class="kw1">echo</span> url_for<span class="br0">&#40;</span><span class="st_h">'article/permalink?subject=finance&amp;year=2006&amp;title=activity-breakdown'</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>&quot;&gt;ここをクリック&lt;/a&gt;
&nbsp;
// ヘルパーはURIがarticle_by_titleルールにマッチすることを見る
// ルーティングシステムはそれから外部URLを作成する
 =&gt; &lt;a href=&quot;http://www.example.com/articles/finance/2006/activity-breakdown.html&quot;&gt;ここをクリック&lt;/a&gt;
&nbsp;
// link_to()ヘルパーは直接ハイパーリンクを出力し
// PHPとHTMLを混合させることを回避する
<span class="kw2">&lt;?php</span> <span class="kw1">echo</span> link_to<span class="br0">&#40;</span>
  <span class="st_h">'ここをクリック'</span><span class="sy0">,</span>
  <span class="st_h">'article/permalink?subject=finance&amp;year=2006&amp;title=activity-breakdown'</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>
) ?&gt;
&nbsp;
// 内部では、link_to()はurl_for()への呼び出しを行うので結果はつぎのものと同じ
=&gt; &lt;a href=&quot;http://www.example.com/articles/finance/2006/activity-breakdown.html&quot;&gt;ここをクリック&lt;/a&gt;</pre>

<p>ルーティングは2つの方法のメカニズムで、すべてのリンクの形式を整える<code>link_to()</code>ヘルパーを使う場合のみに機能します。</p>

<a name="url.rewriting" id="url.rewriting"></a><h2>URLを書き換える</h2>

<p>ルーティングシステムに深く関わるまえに、1つのことをあきらかにする必要があります。以前のセクションで示された例において、内部URIのフロントコントローラー(<code>index.php</code>もしくは<code>myapp_dev.php</code>)の説明をしていません。フロントコントローラーは、アプリケーションの要素ではありませんが、環境を決定します。ですのですべてのリンクは環境に依存しなければならず、フロントコントローラー名は内部URLに決して現れることはありません。</p>

<p>生成されたURLの例にはスクリプト名が存在しません。デフォルトの運用環境では生成されたURLはスクリプト名を含まないからです。<code>settings.yml</code>ファイルの<code>no_script_name</code>パラメーターは生成されたURL内でフロントコントローラー名の表示を正確にコントロールします。リスト9-5で示されるように、<code>off</code>に設定すれば、リンクヘルパーによるURLの出力はフロントコントローラー名をすべてのリンク内部に記載します。</p>

<p>リスト9-5 - フロントコントローラー名をURL内部に表示する(<code>apps/myapp/config/settings.yml</code>)</p>

<pre><code>prod:
  .settings:
    no_script_name:  off
</code></pre>

<p>生成されたURLはつぎのように示されます:</p>

<pre><code>http://www.example.com/index.php/articles/finance/2006/activity-breakdown.html
</code></pre>

<p>運用環境を除いたすべての環境において、<code>no_script_name</code>パラメーターはデフォルトでは<code>off</code>に設定されます。たとえば、開発環境のアプリケーションをブラウザーで見るとき、フロントコントローラー名はつねにURLに表示されます。</p>

<pre><code>http://www.example.com/myapp_dev.php/articles/finance/2006/activity-breakdown.html
</code></pre>

<p>運用環境において、<code>no_script_name</code>パラメーターは<code>on</code>に設定されるので、URLはルーティング情報だけを示し、よりユーザーフレンドリです。技術的な情報は現れません。</p>

<pre><code>http://www.example.com/articles/finance/2006/activity-breakdown.html
</code></pre>

<p>しかしながら、アプリケーションはどのフロントコントローラーが呼び出されるのかどのようにして知るのでしょうか？これはURLの書き換えが行われる場所です。URLのなかに何も存在しないときに、Webサーバーが任意のスクリプトを呼び出すために設定できます。</p>

<p>Apacheにおいて、これはいったん<code>mod_rewrite</code>拡張機能を有効にすれば可能です。すべてのsymfonyのプロジェクトは<code>.htaccess</code>ファイルを備えており、このファイルは<code>web</code>ディレクトリのために<code>mod_rewrite</code>の設定をサーバーの設定に追加します。このファイルのデフォルトの内容はリスト9-6で示されています。</p>

<p>リスト9-6 - Apacheのためのデフォルトの書き換えルール(<code>myproject/web/.htaccess</code>ファイル)</p>

<pre><code>&lt;IfModule mod_rewrite.c&gt;
  RewriteEngine On

  # .somethingを持ったすべてのファイルをスキップする
  # ルートでピリオドを許可するためにつぎの3行をコメントにする
  RewriteCond %{REQUEST_URI} \..+$
  RewriteCond %{REQUEST_URI} !\.html$
  RewriteRule .* - [L]

  # .htmlバージョンがここ(キャッシュ)であるか確認する
  RewriteRule ^$ index.html [QSA]
  RewriteRule ^([^.]+)$ $1.html [QSA]
  RewriteCond %{REQUEST_FILENAME} !-f

  # いいえ、Webのフロントコントローラーにリダイレクトする
  RewriteRule ^(.*)$ index.php [QSA,L]
&lt;/IfModule&gt;
</code></pre>

<p>Webサーバーは受けとったURLの形式を検査します。URLがサフィックスを含まず、かつ利用可能なページのキャッシュバージョンが存在しない場合、リクエストは<code>index.php</code>に渡されます(12章でキャッシュを説明します)。</p>

<blockquote class="tip"><p>
  route内でピリオドを許可するには、<code>.htaccess</code>ファイルで最初の2つの書き換え条件と最初の書き換えルールをコメントにします。</p>
</blockquote>

<p>しかしながら、symfonyのプロジェクトの<code>web/</code>ディレクトリはプロジェクトのすべてのアプリケーションと環境のあいだで共有されます。これは通常の場合フロントコントローラーが<code>web</code>ディレクトリのなかに複数存在することを意味します。たとえば、<code>frontend</code>アプリケーションと<code>backend</code>アプリケーション、と<code>dev</code>環境と<code>prod</code>環境を持つプロジェクトは4つのフロントコントローラーのスクリプトを<code>web/</code>ディレクトリに含めます:</p>

<pre><code>index.php         // prodのfrontend
frontend_dev.php  // devのfrontend
backend.php       // prodのbackend
backend_dev.php   // devのbackend
</code></pre>

<p>mod_rewriteの設定はデフォルトのスクリプトの名前だけを指定します。すべてのアプリケーションと環境に対して<code>no_script_name</code>を<code>on</code>に設定する場合、すべてのURLは<code>prod</code>環境の<code>frontend</code>アプリケーションへのリクエストとして解釈されます。これが任意のプロジェクトに対してURLの書き換えを利用できる1つの環境を持つアプリケーションを1つだけ持つことができる理由です。</p>

<blockquote class="tip"><p>
  スクリプトの名前を持たないアプリケーションを複数持つ方法が1つあります。サブディレクトリをwebのrootに作り、フロントコントローラーをこれらの内部に移動させます。<code>SF_ROOT_DIR</code>定数の定義を相応に変更し、それぞれのアプリケーションに対して必要な<code>.htaccess</code>ファイルのURL書き換え設定を作ります。</p>
</blockquote>

<a name="link.helpers" id="link.helpers"></a><h2>リンクヘルパー</h2>

<p>ルーティングシステムに対して、テンプレート内では通常の<code>&lt;a&gt;</code>タグの代わりにリンクヘルパーを使うべきです。これをやっかいな問題と見なさず、むしろ、アプリケーションをきれいな状態に保ち維持しやすくするための機会として見てください。加えて、リンクヘルパーはとても便利で見逃せないショートカットをいくつか提供します。</p>

<a name="hyperlinks.buttons.and.forms" id="hyperlinks.buttons.and.forms"></a><h3>ハイパーリンク、ボタン、とフォーム</h3>

<p><code>link_to()</code>ヘルパーはすでにご存じのとおりです。このヘルパーはXHTML準拠のハイパーリンクを出力し、2つのパラメーター: クリック可能な要素とそれが指し示すリソースの内部URI、を必要とします。ハイパーリンクの代わりに、ボタンが欲しい場合、<code>button_to()</code>ヘルパーを使います。フォームも<code>action</code>属性の値を管理するヘルパーを持ちます。つぎの章でフォームについてさらに学ぶことになります。リスト9-7はリンクヘルパーのいくつかの例を示します。</p>

<p>リンク 9-7 - <code>&lt;a&gt;</code>、<code>&lt;input&gt;</code>、<code>&lt;form&gt;</code>タグのためのリンクヘルパー</p>

<pre class="php">// 文字列上のハイパーリンク
<span class="kw2">&lt;?php</span> <span class="kw1">echo</span> link_to<span class="br0">&#40;</span><span class="st_h">'my article'</span><span class="sy0">,</span> <span class="st_h">'article/read?title=Finance_in_France'</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>
 =&gt; &lt;a href=&quot;/routed/url/to/Finance_in_France&quot;&gt;my article&lt;/a&gt;
&nbsp;
// 画像上のハイパーリンク
<span class="kw2">&lt;?php</span> <span class="kw1">echo</span> link_to<span class="br0">&#40;</span>image_tag<span class="br0">&#40;</span><span class="st_h">'read.gif'</span><span class="br0">&#41;</span><span class="sy0">,</span> <span class="st_h">'article/read?title=Finance_in_France'</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>
 =&gt; &lt;a href=&quot;/routed/url/to/Finance_in_France&quot;&gt;&lt;img src=&quot;/images/read.gif&quot; /&gt;&lt;/a&gt;
&nbsp;
// ボタンタグ
<span class="kw2">&lt;?php</span> <span class="kw1">echo</span> button_to<span class="br0">&#40;</span><span class="st_h">'my article'</span><span class="sy0">,</span> <span class="st_h">'article/read?title=Finance_in_France'</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>
 =&gt; &lt;input value=&quot;my article&quot; type=&quot;button&quot;onclick=&quot;document.location.href='/routed/url/to/Finance_in_France';&quot; /&gt;
&nbsp;
// フォームタグ
<span class="kw2">&lt;?php</span> <span class="kw1">echo</span> form_tag<span class="br0">&#40;</span><span class="st_h">'article/read?title=Finance_in_France'</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>
 =&gt; &lt;form method=&quot;post&quot; action=&quot;/routed/url/to/Finance_in_France&quot; /&gt;</pre>

<p>絶対URL(<code>http://</code>で始まり、ルーティングシステムで無視される)とアンカーと同様に、リンクヘルパーは内部URIを受けとります。実際の世界のアプリケーションにおいて、内部URIは動的なパラメーターで作られます。リスト9-8はこれらすべての事例を示します。</p>

<p>リスト9-8 - リンクヘルパーが受けとるURL</p>

<pre class="php">// 内部のURI
<span class="kw2">&lt;?php</span> <span class="kw1">echo</span> link_to<span class="br0">&#40;</span><span class="st_h">'my article'</span><span class="sy0">,</span> <span class="st_h">'article/read?title=Finance_in_France'</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>
 =&gt; &lt;a href=&quot;/routed/url/to/Finance_in_France&quot;&gt;my article&lt;/a&gt;
&nbsp;
// 動的なパラメーターを持つ内部URI
<span class="kw2">&lt;?php</span> <span class="kw1">echo</span> link_to<span class="br0">&#40;</span><span class="st_h">'my article'</span><span class="sy0">,</span> <span class="st_h">'article/read?title='</span><span class="sy0">.</span><span class="re0">$article</span><span class="sy0">-&gt;</span><span class="me1">getTitle</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>
&nbsp;
// 著者を持つ内部URI
<span class="kw2">&lt;?php</span> <span class="kw1">echo</span> link_to<span class="br0">&#40;</span><span class="st_h">'my article'</span><span class="sy0">,</span> <span class="st_h">'article/read?title=Finance_in_France#foo'</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>
 =&gt; &lt;a href=&quot;/routed/url/to/Finance_in_France#foo&quot;&gt;my article&lt;/a&gt;
&nbsp;
// 絶対URL
<span class="kw2">&lt;?php</span> <span class="kw1">echo</span> link_to<span class="br0">&#40;</span><span class="st_h">'my article'</span><span class="sy0">,</span> <span class="st_h">'http://www.example.com/foobar.html'</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>
 =&gt; &lt;a href=&quot;http://www.example.com/foobar.html&quot;&gt;my article&lt;/a&gt;</pre>

<a name="link.helper.options" id="link.helper.options"></a><h3>リンクヘルパーのオプション</h3>

<p>7章で説明したように、ヘルパーは、連想配列もしくは文字列である、追加オプション引数を受けとります。リスト9-9で示されているように、これはリンクヘルパーにもあてはまります。</p>

<p>リスト9-9 - リンクヘルパーは追加オプションを受けとる</p>

<pre class="php">// 連想配列としての追加オプション
<span class="kw2">&lt;?php</span> <span class="kw1">echo</span> link_to<span class="br0">&#40;</span><span class="st_h">'my article'</span><span class="sy0">,</span> <span class="st_h">'article/read?title=Finance_in_France'</span><span class="sy0">,</span> <span class="kw3">array</span><span class="br0">&#40;</span>
  <span class="st_h">'class'</span>  <span class="sy0">=&gt;</span> <span class="st_h">'foobar'</span><span class="sy0">,</span>
  <span class="st_h">'target'</span> <span class="sy0">=&gt;</span> <span class="st_h">'_blank'</span>
<span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>
&nbsp;
// 文字列としての追加オプション(同じ結果)
<span class="kw2">&lt;?php</span> <span class="kw1">echo</span> link_to<span class="br0">&#40;</span><span class="st_h">'my article'</span><span class="sy0">,</span> <span class="st_h">'article/read?title=Finance_in_France'</span><span class="sy0">,</span><span class="st_h">'class=foobar target=_blank'</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>
 =&gt; &lt;a href=&quot;/routed/url/to/Finance_in_France&quot; class=&quot;foobar&quot; target=&quot;_blank&quot;&gt;my article&lt;/a&gt;</pre>

<p>リンクヘルパーに対してsymfony固有のオプション(<code>confirm</code>と<code>popup</code>)の1つも追加できます。リスト9-10で示されるように、最初のオプションはリンクがクリックされたときにJavaScriptの確認ダイアログボックスが表示され、2番目のオプションは新しいウィンドウにリンクが開かれます。</p>

<p>リスト9-10 - リンクヘルパーのための<code>'confirm'</code>オプションと<code>'popup'</code>オプション</p>

<pre class="php"><span class="kw2">&lt;?php</span> <span class="kw1">echo</span> link_to<span class="br0">&#40;</span><span class="st_h">'アイテムを削除する'</span><span class="sy0">,</span> <span class="st_h">'item/delete?id=123'</span><span class="sy0">,</span> <span class="st_h">'confirm=Are you sure?'</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>
 =&gt; &lt;a onclick=&quot;return confirm('よろしいですか？');&quot;
       href=&quot;/routed/url/to/delete/123.html&quot;&gt;delete item&lt;/a&gt;
&nbsp;
<span class="kw2">&lt;?php</span> <span class="kw1">echo</span> link_to<span class="br0">&#40;</span><span class="st_h">'カートに追加する'</span><span class="sy0">,</span> <span class="st_h">'shoppingCart/add?id=100'</span><span class="sy0">,</span> <span class="st_h">'popup=true'</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>
 =&gt; &lt;a onclick=&quot;window.open(this.href);return false;&quot;
       href=&quot;/fo_dev.php/shoppingCart/add/id/100.html&quot;&gt;カートに追加する&lt;/a&gt;
&nbsp;
<span class="kw2">&lt;?php</span> <span class="kw1">echo</span> link_to<span class="br0">&#40;</span><span class="st_h">'カートに追加する'</span><span class="sy0">,</span> <span class="st_h">'shoppingCart/add?id=100'</span><span class="sy0">,</span> <span class="kw3">array</span><span class="br0">&#40;</span>
  <span class="st_h">'popup'</span> <span class="sy0">=&gt;</span> <span class="kw3">array</span><span class="br0">&#40;</span><span class="st_h">'popupWindow'</span><span class="sy0">,</span> <span class="st_h">'width=310,height=400,left=320,top=0'</span><span class="br0">&#41;</span>
<span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>
 =&gt; &lt;a onclick=&quot;window.open(this.href,'popupWindow','width=310,height=400,left=320,top=0');return false;&quot;
       href=&quot;/fo_dev.php/shoppingCart/add/id/100.html&quot;&gt;カートに追加する&lt;/a&gt;</pre>

<p>これらのオプションを結びつけることができます。</p>

<a name="fake.get.and.post.options" id="fake.get.and.post.options"></a><h3>フェイクのGETとPOSTオプション</h3>

<p>時にWeb開発者は実際にはPOSTを行うためにGETリクエストを使います。たとえば、つぎのURLを考えてみてください:</p>

<pre><code>http://www.example.com/index.php/shopping_cart/add/id/100
</code></pre>

<p>このリクエストは品物をショッピングカートのオブジェクトに追加することで、アプリケーションに含まれるデータを変更します。そしてデータはセッションもしくはデータベースに保存されます。このURLはブックマークされ、キャッシュされ、検索エンジンのインデックスに登録されます。すべての嫌なことがデータベースもしくはこのテクニックを使うWebサイトの評価指標に起こることを想像してみてください。当然のことながら、このリクエストはPOSTとして見なされるべきです。なぜなら検索エンジンのロボットはインデックスの上ではPOSTリクエストを行わないからです。</p>

<p>symfonyは<code>link_to()</code>ヘルパー、もしくは<code>button_to()</code>ヘルパーへの呼び出しを実際のPOSTに変換する方法を提供します。リスト9-11で示されるように、<code>post=true</code>オプションを追加するだけです。</p>

<p>リスト9-11 -リンク呼び出しをPOSTリクエストにする</p>

<pre class="php"><span class="kw2">&lt;?php</span> <span class="kw1">echo</span> link_to<span class="br0">&#40;</span><span class="st_h">'ショッピングカートに移動する'</span><span class="sy0">,</span> <span class="st_h">'shoppingCart/add?id=100'</span><span class="sy0">,</span> <span class="st_h">'post=true'</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>
 =&gt; &lt;a onclick=&quot;f = document.createElement('form'); document.body.appendChild(f);
                f.method = 'POST'; f.action = this.href; f.submit();return false;&quot;
       href=&quot;/shoppingCart/add/id/100.html&quot;&gt;ショッピングカートに移動する&lt;/a&gt;</pre>

<p>この<code>&lt;a&gt;</code>タグは<code>href</code>属性を持ち、検索エンジンのロボットなどの、JavaScriptサポートを持たないブラウザーはデフォルトのGETを行いリンクの後に続きます。ですので、POSTメソッドだけに応答するように、アクションの始めにつぎのようなコードを追加することで、アクションを制限しなければなりません:</p>

<pre class="php"><span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">forward404If</span><span class="br0">&#40;</span><span class="re0">$request</span><span class="sy0">-&gt;</span><span class="me1">getMethod</span><span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="sy0">!=</span> sfRequest<span class="sy0">::</span><span class="me2">POST</span><span class="br0">&#41;</span><span class="sy0">;</span></pre>

<p>このオプションは独自の<code>&lt;form&gt;</code>タグを生成するので、フォームに設置されたリンク上でこのオプションが使われていないことを確認してください。</p>

<p>実際にデータを投稿するリンクをPOSTとしてタグ付けすることはよい習慣です。</p>

<a name="forcing.request.parameters.as.get.variables" id="forcing.request.parameters.as.get.variables"></a><h3>リクエストパラメーターをGET変数として強制する</h3>

<p>ルーティングルールに従えば、パラメーターとして<code>link_to()</code>ヘルパーに渡された変数はパターンに変換されます。<code>routing.yml</code>ファイルで内部URIにマッチするルールが存在しない場合、リスト9-12で示されるように、デフォルトのルールは<code>module/action?key=value</code>を<code>/module/action/key/value</code>に変換します。</p>

<p>リスト9-12 - デフォルトのルーティングルール</p>

<pre class="php"><span class="kw2">&lt;?php</span> <span class="kw1">echo</span> link_to<span class="br0">&#40;</span><span class="st_h">'my article'</span><span class="sy0">,</span> <span class="st_h">'article/read?title=Finance_in_France'</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>
=&gt; &lt;a href=&quot;/article/read/title/Finance_in_France&quot;&gt;my article&lt;/a&gt;</pre>

<p>実際にGET構文を保存する必要がある場合、<code>?key=value</code>形式でリクエストパラメーターを渡すために、<code>query_string</code>オプションにおいて、URLパラメーターの外部で強制する必要のある変数を設置します。リスト9-13で示されるように、すべてのリンクヘルパーがこのオプションを受けとります。</p>

<p>リスト9-13 - <code>query_string</code>オプションでGET変数を強制する</p>

<pre class="php"><span class="kw2">&lt;?php</span> <span class="kw1">echo</span> link_to<span class="br0">&#40;</span><span class="st_h">'my article'</span><span class="sy0">,</span> <span class="st_h">'article/read'</span><span class="sy0">,</span> <span class="kw3">array</span><span class="br0">&#40;</span>
  <span class="st_h">'query_string'</span> <span class="sy0">=&gt;</span> <span class="st_h">'title=Finance_in_France'</span>
<span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>
=&gt; &lt;a href=&quot;/article/read?title=Finance_in_France&quot;&gt;my article&lt;/a&gt;</pre>

<p>GET変数として表示されるリクエストパラメーターを持つURLはクライアントサイド上のスクリプト、サーバーサイド上の<code>$_GET</code>と<code>$_REQUEST</code>変数によって解釈されます。</p>

<blockquote class="sidebar"><p class="title">
  <strong>アセットヘルパー</strong></p>
  
  <p>7章でアセットヘルパーの<code>image_tag()</code>、<code>stylesheet_tag()</code>と<code>javascript_include_tag()</code>を紹介しました。これらのヘルパーによって画像、スタイルシート、JavaScriptファイルをレスポンスに含めることができます。これらのアセットへのパスはルーティングルールによって処理されません。これらは公開Webディレクトリの元に実際に設置されたレスポンスにリンクするからです。</p>
  
  <p>アセットに対してファイルの拡張子を記載する必要はありません。symfonyは自動的に<code>.png</code>、<code>.js</code>、もしくは<code>.css</code>の拡張子を画像、JavaScript、もしくはスタイルシートのヘルパー呼び出しに追加します。また、symfonyは<code>web/images/</code>ディレクトリ、<code>web/js/</code>ディレクトリと<code>web/css/</code>ディレクトリで自動的にこれらのアセットを探します。もちろん、特定のファイルフォーマットもしくは特定の場所からのファイルを含めたい場合、正式なファイル名もしくはファイルパスを引数として使います。そして、メディアファイルが明確な名前を持つ場合、symfonyがあなたの代わりに決定するので、<code>alt</code>属性を指定することを悩まずにすみます。</p>

<pre class="php"><span class="kw2">&lt;?php</span> <span class="kw1">echo</span> image_tag<span class="br0">&#40;</span><span class="st_h">'test'</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>
<span class="kw2">&lt;?php</span> <span class="kw1">echo</span> image_tag<span class="br0">&#40;</span><span class="st_h">'test.gif'</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>
<span class="kw2">&lt;?php</span> <span class="kw1">echo</span> image_tag<span class="br0">&#40;</span><span class="st_h">'/my_images/test.gif'</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>
 =&gt; &lt;img href=&quot;/images/test.png&quot; alt=&quot;Test&quot; /&gt;
    &lt;img href=&quot;/images/test.gif&quot; alt=&quot;Test&quot; /&gt;
    &lt;img href=&quot;/my_images/test.gif&quot; alt=&quot;Test&quot; /&gt;</pre>
  
  <p>画像のサイズを修正するには<code>size</code>属性を使います。これは、ピクセル単位の、<code>x</code>で区切られた幅、高さを必要とします。</p>

<pre class="php"><span class="kw2">&lt;?php</span> <span class="kw1">echo</span> image_tag<span class="br0">&#40;</span><span class="st_h">'test'</span><span class="sy0">,</span> <span class="st_h">'size=100x20'</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>
 =&gt; &lt;img href=&quot;/images/test.png&quot; alt=&quot;Test&quot; width=&quot;100&quot; height=&quot;20&quot;/&gt;</pre>
  
  <p>(JavaScriptとスタイルシートに対して)アセットを<code>&lt;head&gt;</code>セクションのなかに含めたい場合、レイアウト内で<code>_tag()</code>バージョンを使う代わりに、テンプレートのなかで<code>use_stylesheet()</code>ヘルパーと<code>use_javascript()</code>ヘルパーを使います。これらのヘルパーはアセットをレスポンスに追加し、<code>&lt;/head&gt;</code>タグがブラウザーに送られるまえにこれらのアセットはインクルードされます。</p>
</blockquote>

<a name="using.absolute.paths" id="using.absolute.paths"></a><h3>絶対パスを使う</h3>

<p>リンクヘルパーとアセットヘルパーはデフォルトで相対パスを生成します。絶対パスへの出力を強制するには、リスト9-14で示されるように、<code>absolute</code>オプションを<code>true</code>に設定します。このテクニックはリンクをEメールのメッセージ、RSSフィード、APIのレスポンスに含めるために便利です。</p>

<p>リスト9-14 - 相対URLの代わりに絶対URLを取得する</p>

<pre class="php"><span class="kw2">&lt;?php</span> <span class="kw1">echo</span> url_for<span class="br0">&#40;</span><span class="st_h">'article/read?title=Finance_in_France'</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>
 =&gt; '/routed/url/to/Finance_in_France'
<span class="kw2">&lt;?php</span> <span class="kw1">echo</span> url_for<span class="br0">&#40;</span><span class="st_h">'article/read?title=Finance_in_France'</span><span class="sy0">,</span> <span class="kw4">true</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>
 =&gt; 'http://www.example.com/routed/url/to/Finance_in_France'
&nbsp;
<span class="kw2">&lt;?php</span> <span class="kw1">echo</span> link_to<span class="br0">&#40;</span><span class="st_h">'finance'</span><span class="sy0">,</span> <span class="st_h">'article/read?title=Finance_in_France'</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>
 =&gt; &lt;a href=&quot;/routed/url/to/Finance_in_France&quot;&gt;finance&lt;/a&gt;
<span class="kw2">&lt;?php</span> <span class="kw1">echo</span> link_to<span class="br0">&#40;</span><span class="st_h">'finance'</span><span class="sy0">,</span> <span class="st_h">'article/read?title=Finance_in_France'</span><span class="sy0">,</span><span class="st_h">'absolute=true'</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>
 =&gt; &lt;a href=&quot; http://www.example.com/routed/url/to/Finance_in_France&quot;&gt;finance&lt;/a&gt;
&nbsp;
// 同じことがアセットヘルパーにあてはまる
<span class="kw2">&lt;?php</span> <span class="kw1">echo</span> image_tag<span class="br0">&#40;</span><span class="st_h">'test'</span><span class="sy0">,</span> <span class="st_h">'absolute=true'</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>
<span class="kw2">&lt;?php</span> <span class="kw1">echo</span> javascript_include_tag<span class="br0">&#40;</span><span class="st_h">'myscript'</span><span class="sy0">,</span> <span class="st_h">'absolute=true'</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span></pre>

<blockquote class="sidebar"><p class="title">
  <strong>メールヘルパー</strong></p>
  
  <p>今日において、Eメール収集ロボットがWebを徘徊するので、一日以内にスパムの餌食にならずにすむEメールアドレスを表示することはできません。symfonyが<code>mail_to</code>ヘルパーを提供する理由はそういうことです。</p>
  
  <p><code>mail_to()</code>ヘルパーは２つのパラメーターをとります: 実際のEメールアドレスと表示される文字列です。追加オプションはHTMLでは全く読めない何かを出力する<code>encode</code>パラメーターを受けとります。ブラウザーはこれを理解できますがロボットは理解できません。</p>

<pre class="php"><span class="kw2">&lt;?php</span> <span class="kw1">echo</span> mail_to<span class="br0">&#40;</span><span class="st_h">'myaddress@mydomain.com'</span><span class="sy0">,</span> <span class="st_h">'contact'</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>
 =&gt; &lt;a href=&quot;mailto:myaddress@mydomain.com'&gt;contact&lt;/a&gt;
<span class="kw2">&lt;?php</span> <span class="kw1">echo</span> mail_to<span class="br0">&#40;</span><span class="st_h">'myaddress@mydomain.com'</span><span class="sy0">,</span> <span class="st_h">'contact'</span><span class="sy0">,</span> <span class="st_h">'encode=true'</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>
 =&gt; &lt;a href=&quot;&amp;#109;&amp;#x61;... &amp;#111;&amp;#x6d;&quot;&gt;&amp;#x63;&amp;#x74;... e&amp;#115;&amp;#x73;&lt;/a&gt;</pre>
  
  <p>エンコードされたEメールのメッセージはランダムな10進法と16進法のエンティティエンコーダによって変換された文字列で構成されます。このトリックは現在のアドレス収集するたいていのスパムボットを停止させますが、収集テクニックは急速に発展していることをご了承ください。</p>
</blockquote>

<a name="routing.configuration" id="routing.configuration"></a><h2>ルーティングの設定</h2>

<p>ルーティングシステムは2つのことを行います:</p>

<ul>
<li>モジュール/アクションとリクエストパラメーターを決定するために、入ってくるリクエストの外部URLを解釈し、内部URIに変換します。</li>
<li>リンクで使われている内部URIを外部URLの形式に整形します(リンクヘルパーを使っていることが前提)。</li>
</ul>

<p>規約はルーティングルールのセットに基づいています。これらのルールはアプリケーションの<code>config/</code>ディレクトリに設置された<code>routing.yml</code>設定ファイルに保存されます。リスト9-15はすべてのsymfonyに搭載されたデフォルトのルーティングルールを示しています。</p>

<p>リスト9-15 - デフォルトのルーティングルール(<code>myapp/config/routing.yml</code>)</p>

<pre><code># デフォルトのルール
homepage:
  url:   /
  param: { module: default, action: index }

default_symfony:
  url:   /symfony/:action/*
  param: { module: default }

default_index:
  url:   /:module
  param: { action: index }

default:
  url:   /:module/:action/*
</code></pre>

<a name="rules.and.patterns" id="rules.and.patterns"></a><h3>ルールとパターン</h3>

<p>ルーティングルールは外部URLと内部URI間の全単射の関係(bijective associations)です。典型的なルールはつぎのように構成されます:</p>

<ul>
<li>ユニークなラベル。これは読みやすさと速さのためにあり、リンクヘルパーのために使われます</li>
<li>マッチするパターン(<code>url</code>キー)</li>
<li>リクエストパラメーターの値の配列(<code>param</code>キー)</li>
</ul>

<p>パターンはワイルドカード(アスタリスクの<code>*</code>で表記される)と名前つきのワイルドカード(コロン、:で始まる)を含むことができます。名前つきのワイルドカードへのマッチはリクエストパラメーターの値になります。たとえば、リスト9-15で定義された<code>default</code>ルールは<code>/foo/bar</code>のようなURLにマッチし、<code>module</code>パラメーターを<code>foo</code>に、<code>action</code>パラメーターを<code>bar</code>に設定します。そして<code>default_symfony</code>ルールにおいて、<code>symfony</code>はキーワードで、<code>action</code>は名前つきのワイルドカードパラメーターです。</p>

<p>ルーティングシステムは<code>routing.yml</code>ファイルを完全に解析し、最初にマッチした時点で止まります。これが独自のルールをデフォルトのルールの上に追加しなければならない理由です。たとえば、URLの<code>/foo/123</code>はリスト9-16で定義された両方のルールにマッチしますが、symfonyは最初<code>my_rule:</code>をテストして、ルールがマッチする場合、<code>default:</code>をテストしません。リクエストは<code>123</code>に設定された<code>bar</code>をともなう<code>mymodule/myaction</code>アクションによって処理されます(そしｔ<code>foo/123</code>アクションによって処理されません)。</p>

<p>リスト9-16 - ルールは完全に解析される</p>

<pre><code>my_rule:
  url:   /foo/:bar
  param: { module: mymodule, action: myaction }

# デフォルトのルール
default:
  url:   /:module/:action/*
</code></pre>

<blockquote class="note"><p>
  新しいアクションが作られたとき、そのためのルーティングルールを作らなければならないということにはなりません。デフォルトの<code>module/action</code>パターンがあなたの用途に合う場合、<code>routing.yml</code>ファイルは忘れてください。しかしながら、アクションの外部URLをカスタマイズしたい場合、デフォルトのルールの上に新しいルールを追加します。</p>
</blockquote>

<p>リスト9-17は<code>article/read</code>アクションに対する外部URL形式の変更プロセスを示しています。</p>

<p>リスト9-17 - <code>artile/read</code>アクションに対して外部URL形式を変更する</p>

<pre class="php"><span class="kw2">&lt;?php</span> <span class="kw1">echo</span> url_for<span class="br0">&#40;</span><span class="st_h">'article/read?id=123'</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>
 =&gt; /article/read/id/123       // デフォルトのフォーマッティング
&nbsp;
// これを/article/123に変更するため、routing.ymlの始めで
// 新しいルールを追加する
article_by_id:
  url:   /article/:id
  param: { module: article, action: read }</pre>

<p>問題はリスト9-17の<code>article_by_id</code>ルールは<code>article</code>モジュールのほかのすべてのアクションに対するデフォルトのルーティングを壊すことです。実際、<code>article/delete</code>のようなURLは<code>default</code>ルールの代わりにこのルールにマッチし、<code>delete</code>アクションの代わりに<code>delete</code>に設定された<code>id</code>をともなう<code>read</code>アクションを呼び出します。この問題を回避するには、<code>article_by_id</code>ルールがワイルドカードである<code>id</code>が整数であるURLだけにマッチするようにパターン制約を追加しなければなりません。</p>

<a name="pattern.constraints" id="pattern.constraints"></a><h3>パターンの制約</h3>

<p>URLが複数のルールにマッチするとき、制約もしくは要件(requirements)をパターンに追加することでルールを洗練させなければなりません。要件は正規表現のセットでマッチするルールのためにワイルドカードによってマッチされなければなりません。</p>

<p>たとえば、<code>id</code>パラメーターが整数であるURLだけにマッチするように<code>article_by_id</code>ルールを修正するには、リスト9-18で示されるように、ルールに一行追加します。</p>

<p>リスト9-18 - 要件(requirements)をルーティングルールに追加する</p>

<pre><code>article_by_id:
  url:   /article/:id
  param: { module: article, action: read }
  requirements: { id: \d+ }
</code></pre>

<p>URLの<code>article/delete</code>は<code>article_by_id</code>にはマッチできません。<code>'delete'</code>の文字列が要件を満たさないからです。それゆえ、ルーティングシステムはつぎのルールでマッチするものを探し続け、最後には<code>default</code>ルールを見つけます。</p>

<blockquote class="sidebar"><p class="title">
  <strong>パーマリンク</strong></p>
  
  <p>ルーティングのためのよいセキュリティのガイドラインは主キーを隠し、これらを可能なかぎり重要な文字列で置き換えることです。これらのIDよりもこれらのタイトルから記事にアクセスしたい場合はどうしますか？これを行うにはつぎのような外部URLになります</p>

<pre><code>http://www.example.com/article/Finance_in_France 
</code></pre>
  
  <p>この範囲に対して、新しい<code>permalink</code>アクションを作成する必要があります。このアクションは<code>id</code>パラメーターの代わりに<code>slug</code>パラメーターを使い、新しいルールを追加します:</p>

<pre><code>article_by_id:
  url:          /article/:id
  param:        { module: article, action: read }
  requirements: { id: \d+ }

article_by_slug:
  url:          /article/:slug
  param:        { module: article, action: permalink }
</code></pre>
  
  <p><code>permalink</code>アクションはタイトルからリクエストされた記事を決定する必要があるので、モデルは適切なメソッドを提供しなければなりません。</p>

<pre class="php"><span class="kw2">public</span> <span class="kw2">function</span> executePermalink<span class="br0">&#40;</span><span class="br0">&#41;</span>
<span class="br0">&#123;</span>
  <span class="re0">$article</span> <span class="sy0">=</span> ArticlePeer<span class="sy0">::</span><span class="me2">retrieveBySlug</span><span class="br0">&#40;</span><span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">getRequestParameter</span><span class="br0">&#40;</span><span class="st_h">'slug'</span><span class="br0">&#41;</span><span class="sy0">;</span>
  <span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">forward404Unless</span><span class="br0">&#40;</span><span class="re0">$article</span><span class="br0">&#41;</span><span class="sy0">;</span>  <span class="co1">// 記事がslugにマッチしない場合404を表示する</span>
  <span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">article</span> <span class="sy0">=</span> <span class="re0">$article</span><span class="sy0">;</span>          <span class="co1">// オブジェクトをテンプレートに渡す</span>
<span class="br0">&#125;</span></pre>
  
  <p>内部URIの正しいフォーマッティングを有効にするために、テンプレートのなかの<code>read</code>アクションへのリンクを<code>permalink</code>アクションへのリンクに置き換えることも必要です。</p>

<pre class="php">// つぎのコードを
<span class="kw2">&lt;?php</span> <span class="kw1">echo</span> link_to<span class="br0">&#40;</span><span class="st_h">'my article'</span><span class="sy0">,</span> <span class="st_h">'article/read?id='</span><span class="sy0">.</span><span class="re0">$article</span><span class="sy0">-&gt;</span><span class="me1">getId</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>
&nbsp;
// 以下のコードに置き換える
<span class="kw2">&lt;?php</span> <span class="kw1">echo</span> link_to<span class="br0">&#40;</span><span class="st_h">'my article'</span><span class="sy0">,</span> <span class="st_h">'article/permalink?slug='</span><span class="sy0">.</span><span class="re0">$article</span><span class="sy0">-&gt;</span><span class="me1">getSlug</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span></pre>
  
  <p><code>requirements</code>の行のおかげで、<code>article_by_id</code>ルールが最初に現れたとしても、<code>/article/Finance_in_France</code>のような外部URLが<code>article_by_slug</code>ルールにマッチします。</p>
  
  <p>slugによって記事が読みとられるので、データベースのパフォーマンスを最適化するにはインデックスを<code>Article</code>モデルの記述内容の<code>slug</code>カラムに追加すべきです。</p>
</blockquote>

<a name="setting.default.values" id="setting.default.values"></a><h3>デフォルト値を設定する</h3>

<p>パラメーターが定義されていなくても、ルールを機能させるために名前つきのワイルドカードにデフォルト値を渡すことができます。デフォルト値を<code>param:</code>配列のなかで設定します。</p>

<p>たとえば、<code>id</code>パラメーターが設定されていない場合<code>article_by_id</code>ルールはマッチしません。リスト9-19で示されるように、強制することができます。</p>

<p>リスト9-19 - ワイルドカードに対してデフォルト値を設定する</p>

<pre><code>article_by_id:
  url:          /article/:id
  param:        { module: article, action: read,
id: 1
 }
</code></pre>

<p>デフォルトのパラメーターはパターン内で見つかるワイルドカードである必要はありません。リスト9-20において、<code>display</code>パラメーターはURLに表示されなくても<code>true</code>の値をとります。</p>

<p>リスト9-20 - リクエストパラメーターのためのデフォルト値を設定する</p>

<pre><code>article_by_id:
  url:          /article/:id
  param:        { module: article, action: read, id: 1, display: true }
</code></pre>

<p>注意深く見ると、パターン内で見つからない<code>module</code>変数と<code>action</code>変数に対して<code>article</code>と<code>read</code>がそれぞれのデフォルト値であることがわかります。</p>

<blockquote class="tip"><p>
  <code>sf_routing_default</code>設定パラメーターを定義することによって、すべてのルーティングルールに対してデフォルトのパラメーターを定義できます。たとえば、デフォルトで<code>theme</code>パラメーターを<code>defult</code>の値に設定するすべてのルールが欲しい場合、<code>sfConfig::set('sf_routing_defaults',array('theme' =&gt; 'default'));</code>の行をアプリケーションの<code>config.php</code>に追加します。</p>
</blockquote>

<a name="speeding.up.routing.by.using.the.rule.name" id="speeding.up.routing.by.using.the.rule.name"></a><h3>ルールの名前を利用してルーティングを加速する</h3>

<p>リスト9-21で示されるように、ルールラベルがアットマーク記号(<code>@</code>)のまえに来る場合、リンクヘルパーはモジュール/アクションの組の代わりにルールラベルを受けとります。</p>

<p>リスト9-21 - モジュール/アクションの代わりにルールラベルを使う</p>

<pre class="php"><span class="kw2">&lt;?php</span> <span class="kw1">echo</span> link_to<span class="br0">&#40;</span><span class="st_h">'my article'</span><span class="sy0">,</span> <span class="st_h">'article/read?id='</span><span class="sy0">.</span><span class="re0">$article</span><span class="sy0">-&gt;</span><span class="me1">getId</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>
&nbsp;
// つぎのように書くこともできる
<span class="kw2">&lt;?php</span> <span class="kw1">echo</span> link_to<span class="br0">&#40;</span><span class="st_h">'my article'</span><span class="sy0">,</span> <span class="st_h">'@article_by_id?id='</span><span class="sy0">.</span><span class="re0">$article</span><span class="sy0">-&gt;</span><span class="me1">getId</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span></pre>

<p>このトリックに関してよい点とわるい点があります、よい点はつぎのとおりです:</p>

<ul>
<li>内部URIの整形がはるかに速く行われます。symfonyはリンクにマッチするルールを見つけるためにすべてのルールを探す必要がないからです。ルーティングされたハイパーリンクをたくさん持つページにおいて、モジュール/アクションの組の代わりにルールラベルを使う場合、速度の押し上げは顕著です。</li>
<li>ルールラベルを使うことはアクションの背後にあるロジックを抽象化するための助けになります。アクション名を変更するがURLはそのままにする場合、<code>routing.yml</code>ファイルのなかで変更を行うだけで十分です。すべての<code>link_to()</code>呼び出しはさらに変更しなくても機能します。</li>
<li>呼び出しのロジックはルール名で明らかです。モジュールとアクションが明確な名前を持つ場合でも、<code>article/display</code>よりも<code>@display_article_by_slug</code>を呼び出したほうがベターです。</li>
</ul>

<p>一方で、わるい点は、新しいハイパーリンクを追加することが自明ではなくなることです。アクションに対してどのラベルが使われているのか解明するために<code>routing.yml</code>ファイルにつねに参照する必要があるからです。</p>

<p>最良の選択はプロジェクト次第です。結局は、あなた次第です。</p>

<blockquote class="tip"><p>
  テストの間(<code>dev</code>環境)、 ブラウザーの任意のリクエストに対してどのルールがマッチしたのかチェックしたい場合、"logs and msgs"セクションのWebデバッグツールバーを展開して、"matched route XXX."を指定する行を探してください。Webデバッグモードに関する詳細な情報は16章で知ることになります。</p>
</blockquote>

<a name="adding.an.html.extension" id="adding.an.html.extension"></a><h3>.html拡張子を追加する</h3>

<p>以下の2つのURLを比較してください:</p>

<pre><code>http://myapp.example.com/article/Finance_in_France
http://myapp.example.com/article/Finance_in_France.html
</code></pre>

<p>同じページであっても、ユーザー(とロボット)はURLなのでこれを違うものとして見るかも知れません。2番目のURLは静的なページの深くてよく整理されたWebディレクトリを呼び出します。静的なページは検索エンジンがインデックスを作成する方法を理解しているWebサイトの種類のものです。</p>

<p>リスト9-22で示されるように、サフィックスをルーティングシステムによって生成されたすべての外部URLに追加するには、<code>settings.yml</code>ファイル内の<code>suffix</code>の値を変更します。</p>

<p>リスト9-22 - すべてのURLに対してサフィックスを設定する(<code>myapp/config/settings.yml</code>)</p>

<pre><code>prod:
  .settings
    suffix:         .html
</code></pre>

<p>デフォルトのサフィックスはピリオド(<code>.</code>)に設定されます。このことはあなたが接尾辞を指定しないかぎりルーティングシステムは接尾辞を追加しないことを意味します。</p>

<p>時に、唯一のルーティングルールのためにサフィックスを指定する必要があります。その場合、リスト9-23で示されるように、接尾辞を<code>routing.yml</code>ファイルの関連する<code>url:</code>の行に直接書きます。グローバルな接尾辞は無視されます。</p>

<p>リスト9-23 - 1つのURLに対してサフィックスを設定する(<code>myapp/config/routing.yml</code>)</p>

<pre><code>article_list:
  url:          /latest_articles
  param:        { module: article, action: list }

article_list_feed:
  url:          /latest_articles.rss
  param:        { module: article, action: list, type: feed }
</code></pre>

<a name="creating.rules.without.routing.yml" id="creating.rules.without.routing.yml"></a><h3>routing.ymlなしでルールを作成する</h3>

<p>たいていの設定ファイルにあてはまることですが、<code>routing.yml</code>ファイルはルーティングルールを定義するための解決方法ですが、唯一の方法ではありません。アプリケーションの<code>config.php</code>ファイル、もしくはフロントコントローラースクリプト内で、しかし<code>dispatch()</code>を呼び出すまえに、PHPでルールを定義できます。なぜなら、このメソッドは現在のルーティングルールにしたがって実行するアクションを決定するからです。PHPでルールを定義することは、設定もしくはほかのパラメーターに依存する、動的なルールを作成することを許可することを意味します。</p>

<p>ルーティングルールを扱うオブジェクトはSingletonの<code>sfRouting</code>です。これは<code>sfRouting::getInstance()</code>メソッドを求めることでコードのあらゆる部分から利用できます。<code>prependRoute()</code>メソッドは<code>routing.yml</code>ファイルで定義された既存のルールの上に新しいルールを追加します。このメソッドは4つのパラメーターを必要とします。これらのパラメーターはルールを定義するために必要とされるパラメーターと同じです: ルートのラベル、パターン、デフォルト値の連想配列と別の要件の連想配列です。たとえば、リスト9-18で示される<code>routing.yml</code>ルールの定義はリスト9-24で示されるPHPコードと同等です。</p>

<p>リスト9-24 - PHPでルールを定義する</p>

<pre class="php">sfRouting<span class="sy0">::</span><span class="me2">getInstance</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span><span class="me1">prependRoute</span><span class="br0">&#40;</span>
  <span class="st_h">'article_by_id'</span><span class="sy0">,</span>                                  <span class="co1">// routeの名前</span>
  <span class="st_h">'/article/:id'</span><span class="sy0">,</span>                                   <span class="co1">// routeパターン</span>
  <span class="kw3">array</span><span class="br0">&#40;</span><span class="st_h">'module'</span> <span class="sy0">=&gt;</span> <span class="st_h">'article'</span><span class="sy0">,</span> <span class="st_h">'action'</span> <span class="sy0">=&gt;</span> <span class="st_h">'read'</span><span class="br0">&#41;</span><span class="sy0">,</span> <span class="co1">// デフォルト値</span>
  <span class="kw3">array</span><span class="br0">&#40;</span><span class="st_h">'id'</span> <span class="sy0">=&gt;</span> <span class="st_h">'\d+'</span><span class="br0">&#41;</span><span class="sy0">,</span>                             <span class="co1">// 要件</span>
<span class="br0">&#41;</span><span class="sy0">;</span></pre>

<p>Singletonの<code>sfRouting</code>は手動でrouteを扱うために便利なほかのメソッド、<code>clearRoutes()</code>、<code>hasRoutes()</code>、<code>getRoutesByName()</code>などを持ちます。もっと学ぶにはAPIドキュメント(<a href="http://www.symfony-project.org/api/1_0/">http://www.symfony-project.org/api/1_0/</a>)を参照してください。</p>

<blockquote class="tip"><p>
  いったんこの本で説明された概念を十分に理解し始めたら、オンラインのAPIドキュメント、もっとベターなのはsymfonyのソースを眺めることで、フレームワークの理解を深めることができます。この本ではsymfonyの調整方法とパラメーターのすべては説明されていません。しかしながら、オンラインドキュメントは無制限です。</p>
</blockquote>

<a name="dealing.with.routes.in.actions" id="dealing.with.routes.in.actions"></a><h2>アクションのなかでrouteを処理する</h2>

<p>現在のrouteについて情報を読みとりたい場合、たとえば将来の"back to page xxx"リンクを用意するために、<code>sfRouting</code>オブジェクトのメソッドを使うべきです。リスト9-25で示されるように、<code>getCurrentInternalUri()</code>メソッドによって返されたURIは、<code>link_to()</code>ヘルパーへの呼び出しで使われます。</p>

<p>リスト9-25 - 現在のrouteについて情報を読みとるために<code>sfRouting</code>オブジェクトを使う</p>

<pre class="php"><span class="co1">// つぎのようなURLを求める場合</span>
http<span class="sy0">:</span><span class="co1">//myapp.example.com/article/21</span>
&nbsp;
<span class="co1">// article/read アクションのなかでつぎのコードを使う</span>
<span class="re0">$uri</span> <span class="sy0">=</span> sfRouting<span class="sy0">::</span><span class="me2">getInstance</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span><span class="me1">getCurrentInternalUri</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>
 <span class="sy0">=&gt;</span> article<span class="sy0">/</span>read?id<span class="sy0">=</span><span class="nu0">21</span>
&nbsp;
<span class="re0">$uri</span> <span class="sy0">=</span> sfRouting<span class="sy0">::</span><span class="me2">getInstance</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span><span class="me1">getCurrentInternalUri</span><span class="br0">&#40;</span><span class="kw4">true</span><span class="br0">&#41;</span><span class="sy0">;</span>
 <span class="sy0">=&gt;</span> <span class="sy0">@</span>article_by_id?id<span class="sy0">=</span><span class="nu0">21</span>
&nbsp;
<span class="re0">$rule</span> <span class="sy0">=</span> sfRouting<span class="sy0">::</span><span class="me2">getInstance</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span><span class="me1">getCurrentRouteName</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>
 <span class="sy0">=&gt;</span> article_by_id
&nbsp;
<span class="co1">// 現在のmodule/action名が必要なだけなら</span>
<span class="co1">// これらが実際のリクエストパラメーターであることを覚えておく</span>
<span class="re0">$module</span> <span class="sy0">=</span> <span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">getRequestParameter</span><span class="br0">&#40;</span><span class="st_h">'module'</span><span class="br0">&#41;</span><span class="sy0">;</span>
<span class="re0">$action</span> <span class="sy0">=</span> <span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">getRequestParameter</span><span class="br0">&#40;</span><span class="st_h">'action'</span><span class="br0">&#41;</span><span class="sy0">;</span></pre>

<p>内部URIを外部URLに変換する必要がある場合、テンプレートのなかで<code>url_for()</code>ヘルパーが行うように、リスト9-26で示されている<code>sfController</code>オブジェクトの<code>genUrl()</code>メソッドを使います。</p>

<p>リスト9-26 - 内部URIを変換するために<code>sfController</code>オブジェクトを使う</p>

<pre class="php"><span class="re0">$uri</span> <span class="sy0">=</span> <span class="st_h">'article/read?id=21'</span><span class="sy0">;</span>
&nbsp;
<span class="re0">$url</span> <span class="sy0">=</span> <span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">getController</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span><span class="me1">genUrl</span><span class="br0">&#40;</span><span class="re0">$uri</span><span class="br0">&#41;</span><span class="sy0">;</span>
 <span class="sy0">=&gt;</span> <span class="sy0">/</span>article<span class="sy0">/</span><span class="nu0">21</span>
&nbsp;
<span class="re0">$url</span> <span class="sy0">=</span> <span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">getController</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span><span class="me1">genUrl</span><span class="br0">&#40;</span><span class="re0">$uri</span><span class="sy0">,</span> <span class="kw4">true</span><span class="br0">&#41;</span><span class="sy0">;</span>
<span class="sy0">=&gt;</span> http<span class="sy0">:</span><span class="co1">//myapp.example.com/article/21</span></pre>

<a name="summary" id="summary"></a><h2>まとめ</h2>

<p>ルーティング(routing)は外部URLの形式をよりユーザーフレンドリにするために設計された2つの方法を持つメカニズムです。それぞれのプロジェクトの1つのアプリケーションのURL内部でフロントコントローラーの名前を省略できるようにするにはURLの書き換え(URL rewriting)が必要です。ルーティングシステムが両方の方法で機能することを望むのであれば、URLをテンプレート内部に出力する必要があるたびにリンクヘルパーを使わなければなりません。<code>routing.yml</code>ファイルはルーティングシステムのルールを設定し、優先順位とルールの要件(requirements)を使います。<code>settings.yml</code>ファイルはフロントコントローラーの名前と外部URLで可能なプレフィックスの存在に関する追加設定を含みます。</p>
</div>
<div class="navigation">
<hr/>
<table width="100%">
<tr>
<td width="40%" align="left"><a href="08-Inside-the-Model-Layer.html">前の章</a></td>
<td width="20%" align="center"><a href="index.html">ホーム</a></td>
<td width="40%" align="right"><a href="10-Forms.html">次の章</a></td>
</tr>
</table>

</div>
</body>

</html>
